package com.ruoyi.word.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.baidu.TransWebApi;
import com.ruoyi.common.utils.file.QiniuImageUploader;
import com.ruoyi.common.utils.youdao.FanyiV3Util;
import com.ruoyi.common.domain.word.*;
import com.ruoyi.common.domain.word.vo.*;
import com.ruoyi.word.dao.mapper.CommonWordMapper;
import com.ruoyi.word.dao.mapper.CommonWordPronounceMapper;
import com.ruoyi.word.dao.mapper.CommonWordRetryRecordMapper;
import com.ruoyi.word.service.ICommonWordPronounceService;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;

@Service
public class CommonWordPronounceServiceImpl implements ICommonWordPronounceService {
    public final Logger logger= LoggerFactory.getLogger(this.getClass());
    @Autowired
    private CommonWordPronounceMapper dao;
    @Autowired
    private CommonWordRetryRecordMapper retryRecordDao;

    @Autowired
    private CommonWordMapper commonWordDao;

    @Value("${upload.bucketCommon}")
    private String bucket;

    @Override
    public int saveByWord(CommonWord word, List<CommonWordPronounce> recordList) {
        dao.deleteByWid(word.getId());
        if(CollectionUtils.isEmpty(recordList)) {
            return 0;
        }
        recordList.stream().forEach(record -> {
            dao.insertSelective(record);
        });
        return 1;
    }

    @Override
    public List<CommonWordPronounce> findByWid(Long wid) {
        return dao.findByWord(wid);
    }

    @Override
    public int deleteByWid(Long wid) {
        return dao.deleteByWid(wid);
    }

    @Override
    @Async
    public void compensationAll() {
        logger.info("=============== word compensation start ===============");
        int pageSize = 100;
        //查询所有的单词和单词发音
        while (true){
            try {
                List<CommonWordVo> words = commonWordDao.getNullPronounceListLimit(0,pageSize);

                words.stream().forEach(e -> {
                    //拿到百度翻译回来的数据
                    Map<String, String> baiduData = baiduData(e.getName());
                    if(baiduData.get("error") != null){
                        return;
                    }
                    //如果返回的Data长度是4，则直接插入到发音表中结束该单词操作，进入下一个单词操作
                    int type = 0;
                    List<CommonWordPronounce> pronounces = new ArrayList();
                    //存储音标数据
                    if(baiduData.get("phEn") != null && baiduData.get("audioUrlEn") != null){
                        CommonWordPronounce pronounce = new CommonWordPronounce();
                        pronounce.setAddTime(new Date());
                        pronounce.setWid(e.getId());
                        pronounce.setType(1);
                        pronounce.setContent(baiduData.get("phEn"));
                        pronounce.setAudio(baiduData.get("audioUrlEn"));
                        pronounces.add(pronounce);
                    }else{
                        type = 1;
                    }
                    if(baiduData.get("phAm") != null && baiduData.get("audioUrlAm") != null){
                        CommonWordPronounce pronounce2 = new CommonWordPronounce();
                        pronounce2.setAddTime(new Date());
                        pronounce2.setWid(e.getId());
                        pronounce2.setType(2);
                        pronounce2.setContent(baiduData.get("phAm"));
                        pronounce2.setAudio(baiduData.get("audioUrlAm"));
                        pronounces.add(pronounce2);
                    }else{
                        if(type == 1){
                            type = 3;
                        }else{
                            type = 2;
                        }
                    }

                    if(pronounces.size() > 0){
                        CommonWord commonWord = new CommonWord();
                        commonWord.setId(e.getId());
                        saveByWord(commonWord,pronounces);
                    }
                    if(type != 0){
                        saveWordRetryRecord(e.getName(),e.getId(),type,"百度翻译未查到结果");
                    }
                    //否则缺失数据，走有道云接口
//                    Map<String, String> youdaoData = youdaoData(e.getName());
//
//                    //长度大于等于2且小于4，说明音标获取成功，音频获取失败
//                    if(baiduData.size() >= 2 && baiduData.size() < 4){
//                        if(StringUtils.isNotEmpty(youdaoData.get("audioUrlEn"))){
//                            baiduData.put("audioUrlEn",youdaoData.get("audioUrlEn"));
//                        }
//                        if(StringUtils.isNotEmpty(youdaoData.get("audioUrlAm"))){
//                            baiduData.put("audioUrlAm",youdaoData.get("audioUrlAm"));
//                        }
//                        //存储音标数据
//                        pronounceSave(e.getId(),e.getName(),baiduData.get("phEn"),baiduData.get("audioUrlEn"),1);
//                        pronounceSave(e.getId(),e.getName(),baiduData.get("phAm"),baiduData.get("audioUrlAm"),2);
//                        return;
//                    }else{ //否则就查询单词的所有数据（即音标和音频）
//                        //说明有报错
//                        if(StringUtils.isNotEmpty(youdaoData.get("error"))){
//                            //如果有道返回只有错误信息，说明百度和有道都没有查询到单词数据
//                            if(youdaoData.size() == 1){
//                                try {
//                                    saveWordRetryRecord(e.getName(),e.getId(),3,"百度和有道均未查到该单词音标、语音。"+youdaoData.get("error"));
//                                }catch (Exception e1){
//                                    logger.error(e1.toString());
//                                }
//                                return;
//                            }
//                        }
//                        pronounceSave(e.getId(),e.getName(),youdaoData.get("phEn"),youdaoData.get("audioUrlEn"),1);
//                        pronounceSave(e.getId(),e.getName(),youdaoData.get("phAm"),youdaoData.get("audioUrlAm"),2);
//                        return;
//                    }
                });
                if(words.size() < pageSize){
                    logger.info("=============== word compensation over ===============");
                    return;
                }
            }catch (Exception e){
                logger.error("word compensation getNullPronounceListLimit error ---> ",e);
            }
        }
    }

    @Override
    @Async
    public void contentIsNullSave() {
        int pageSize = 100;
        while (true){
            try {
                //获取所有音标为空的数据
                List<CommonWordPronounceVo> pronounceVos = dao.findByContentIsNull(0,pageSize);
                pronounceVos.stream().forEach(e -> {
                    Map<String, String> baiduData = baiduData(e.getName(),false);
                    if(baiduData.get("error") != null){
//                        try {
//                            Thread.sleep(1000);
//                        }catch (Exception exception){
//                            logger.error(exception.getCause().toString());
//                        }

                        return;
                    }
                    String content = null;
                    //1英式；2美式
                    if(1 == e.getType()){
                        content = baiduData.get("phEn");
                    }else if(2 == e.getType()){
                        content = baiduData.get("phAm");
                    }

                    //删除音标数据补全重试记录
                    Example example = new Example(CommonWordRetryRecord.class);
                    example.createCriteria().andEqualTo("wid",e.getWid()).andEqualTo("type",e.getType()).andEqualTo("deleted",0);
                    CommonWordRetryRecord commonWordRetryRecord = retryRecordDao.selectOneByExample(example);
                    if(StringUtils.isNotEmpty(content)){
                        //填补音标为空的数据
                        CommonWordPronounce pronounce = new CommonWordPronounce();
                        pronounce.setId(e.getId());
                        pronounce.setContent(content);
                        dao.updateByPrimaryKeySelective(pronounce);
                        if(commonWordRetryRecord == null){
                            return;
                        }
                        //删除重试记录
                        commonWordRetryRecord.setDeleted(true);
                        retryRecordDao.updateByPrimaryKeySelective(commonWordRetryRecord);
                        return;
                    }
                    //如果数据百度翻译查不到，判断是否做了重试标记，没有则加上重试标记
                    if(commonWordRetryRecord == null){
                        Date date = new Date();
                        commonWordRetryRecord = new CommonWordRetryRecord();
                        commonWordRetryRecord.setFailMsg("百度翻译未查到结果");
                        commonWordRetryRecord.setWid(e.getWid());
                        commonWordRetryRecord.setType(e.getType());
                        commonWordRetryRecord.setName(e.getName());
                        commonWordRetryRecord.setUpdateTime(date);
                        commonWordRetryRecord.setAddTime(date);
                        retryRecordDao.insertSelective(commonWordRetryRecord);

                    }
                });
                if(pronounceVos.size() < pageSize){
                    return;
                }
            }catch (Exception e){
                logger.error("saveContentIsNull error -> ",e);
            }
        }
    }

    @Override
    public List<CommonWordPronounce> findById(Long id) {
        Example example = new Example(CommonWordPronounce.class);
        example.createCriteria().andEqualTo("wid", id);
        return dao.selectByExample(example);
    }

    @Override
    public Map<String, Object> doBaiduPull(CommonWord word) {
        HashMap<String, Object> result = new HashMap<>();
        Map<String, String> baiduData = baiduData(word.getName());
        if(baiduData.get("error") != null){
            result.put("flag", false);
            result.put("msg", "拉取失败，请稍后重试");
            return result;
        }

        //type标识。0、未拉到数据；1、只拉到英式；2、只拉到美式；3、拉到所有
        int type = 0;
        List<CommonWordPronounce> pronounces = new ArrayList();
        //存储音标数据
        //英式发音和音标
        if(baiduData.get("phEn") != null && baiduData.get("audioUrlEn") != null){
            CommonWordPronounce pronounce = new CommonWordPronounce();
            pronounce.setAddTime(new Date());
            pronounce.setWid(word.getId());
            pronounce.setType(1);
            pronounce.setContent(baiduData.get("phEn"));
            pronounce.setAudio(baiduData.get("audioUrlEn"));
            pronounces.add(pronounce);
            type = 1;
        }
        //美式发音和音标
        if(baiduData.get("phAm") != null && baiduData.get("audioUrlAm") != null){
            CommonWordPronounce pronounce2 = new CommonWordPronounce();
            pronounce2.setAddTime(new Date());
            pronounce2.setWid(word.getId());
            pronounce2.setType(2);
            pronounce2.setContent(baiduData.get("phAm"));
            pronounce2.setAudio(baiduData.get("audioUrlAm"));
            pronounces.add(pronounce2);
            if(type == 1){
                type = 3;
            }else {
                type = 2;
            }
        }

        if(type > 0){
            CommonWord commonWord = new CommonWord();
            commonWord.setId(word.getId());
            saveByWord(commonWord,pronounces);
        }

        switch (type){
            case 0:
                result.put("flag", false);
                result.put("msg", "未拉到百度翻译数据");
                break;
            case 1:
                result.put("flag", true);
                result.put("msg", "只拉取到英式数据");
                break;
            case 2:
                result.put("flag", true);
                result.put("msg", "只拉取到美式数据");
                break;
            case 3:
                result.put("flag", true);
                result.put("msg", "拉取成功");
                break;
        }
        return result;
    }

    @Override
    public Map<String, Object> doYoudaoPull(CommonWord word) {
        HashMap<String, Object> result = new HashMap<>();
        Map<String, String> youdaoData = youdaoData(word.getName());
        if(youdaoData.get("error") != null){
            result.put("flag", false);
            result.put("msg", "拉取失败，请稍后重试");
            return result;
        }

        //type标识。0、未拉到数据；1、只拉到英式；2、只拉到美式；3、拉到所有
        int type = 0;
        List<CommonWordPronounce> pronounces = new ArrayList();
        //存储音标数据
        //英式发音和音标
        if(youdaoData.get("phEn") != null && youdaoData.get("audioUrlEn") != null){
            CommonWordPronounce pronounce = new CommonWordPronounce();
            pronounce.setAddTime(new Date());
            pronounce.setWid(word.getId());
            pronounce.setType(1);
            pronounce.setContent(youdaoData.get("phEn"));
            pronounce.setAudio(youdaoData.get("audioUrlEn"));
            pronounces.add(pronounce);
            type = 1;
        }
        //美式发音和音标
        if(youdaoData.get("phAm") != null && youdaoData.get("audioUrlAm") != null){
            CommonWordPronounce pronounce2 = new CommonWordPronounce();
            pronounce2.setAddTime(new Date());
            pronounce2.setWid(word.getId());
            pronounce2.setType(2);
            pronounce2.setContent(youdaoData.get("phAm"));
            pronounce2.setAudio(youdaoData.get("audioUrlAm"));
            pronounces.add(pronounce2);
            if(type == 1){
                type = 3;
            }else {
                type = 2;
            }
        }

        if(type > 0){
            CommonWord commonWord = new CommonWord();
            commonWord.setId(word.getId());
            saveByWord(commonWord,pronounces);
        }

        switch (type){
            case 0:
                result.put("flag", false);
                result.put("msg", "未拉到有道翻译数据");
                break;
            case 1:
                result.put("flag", true);
                result.put("msg", "只拉取到英式数据");
                break;
            case 2:
                result.put("flag", true);
                result.put("msg", "只拉取到美式数据");
                break;
            case 3:
                result.put("flag", true);
                result.put("msg", "拉取成功");
                break;
        }
        return result;
    }

    @Override
    public List<CommonWordPronounce> findByWids(List<Long> wids) {
        return dao.findByWords(wids);
    }

    private List<CommonWordRetryRecord> findCommonWordRetryRecordByWidAndType(Long wid,Integer type){
        Example example = new Example(CommonWordRetryRecord.class);
        example.createCriteria().andEqualTo("wid",wid).andEqualTo("deleted",0);
        return retryRecordDao.selectByExample(example);
    }

    /**
     * 插入音标数据
     * @param wid 单词ID
     * @param content 音标
     * @param audio 音频地址
     * @param type 发音方式；1、英式；2、美式
     */
    private void pronounceSave(Long wid,String name, String content,String audio,Integer type){
        CommonWordPronounce pronounce = new CommonWordPronounce();
        pronounce.setAddTime(new Date());
        pronounce.setWid(wid);
        pronounce.setType(type);
        pronounce.setContent(content);
        pronounce.setAudio(audio);
        int i = dao.insertSelective(pronounce);
//        String msg = null;
//        try {
//            int i = dao.insertSelective(pronounce);
//            if( i <= 0 ){
//                msg = "数据库存储失败，返回值"+ i;
//                try {
//                    saveWordRetryRecord(name,wid,type,msg);
//                }catch (Exception exception){
//                    logger.error(exception.getCause().toString());
//                }
//
//            }
//        }catch (Exception e){
//            msg = e.getMessage();
//            saveWordRetryRecord(name,wid,type,msg);
//        }

    }

    /**
     *
     * @param name
     * @param wid
     * @param type 1、英式，2、美式、3、两种都失败
     * @param msg
     */
    public void saveWordRetryRecord(String name,Long wid,Integer type,String msg){
        Example example = new Example(CommonWordRetryRecord.class);
        example.createCriteria().andEqualTo("name",name).andEqualTo("type",type).andEqualTo("deleted",0);
        CommonWordRetryRecord commonWordRetryRecord = retryRecordDao.selectOneByExample(example);
        if(commonWordRetryRecord != null){
            return;
        }
        commonWordRetryRecord = new CommonWordRetryRecord();
        Date date = new Date();
        commonWordRetryRecord.setAddTime(date);
        commonWordRetryRecord.setUpdateTime(date);
        commonWordRetryRecord.setName(name);
        commonWordRetryRecord.setWid(wid);
        commonWordRetryRecord.setFailMsg(msg);
        commonWordRetryRecord.setType(type);
        retryRecordDao.insertSelective(commonWordRetryRecord);
    }

    /**
     * 有道翻译接口
     * @param word 单词
     * @return
     */
    private Map<String,String> youdaoData(String word){
        Map data = new HashMap();
        try {
            String resultStr = FanyiV3Util.trans(word);
            JSONObject result = JSON.parseObject(resultStr);
            if(result == null || result.getJSONObject("basic") == null) {
                data.put("error","baidu select null");
                throw new RuntimeException("youdao: result is null");
            }

            JSONObject basic = result.getJSONObject("basic");
            //获取英式音标
            String phEn = basic.getString("uk-phonetic");
            //获取美式音标
            String phAm = basic.getString("us-phonetic");
            logger.info("有道解析：" + word);
            logger.info("美式音标：" + phAm);
            logger.info("英式音标：" + phEn);
            data.put("phAm",phAm);
            data.put("phEn",phEn);
            try {
                //获取英式音标音频
                String audioUrlEn = uploadToQiniu(word.trim(), "1");
                data.put("audioUrlEn",audioUrlEn);
                //获取美式音标音频
                String audioUrlAm = uploadToQiniu(word.trim(), "2");
                data.put("audioUrlAm",audioUrlAm);

            }catch (Exception exception){
                logger.error("youdao: word upload error to Qiniu ---> word:{}",word,exception);
                String failMsg = "有道上传音频地址失败：" + exception.getMessage();
                data.put("error",failMsg);
            }

        }catch (Exception e){
            logger.error("youdao data error ----> word:{}",word,e);
            data.put("error", e.getMessage());
            return data;
        }
        return data;
    }

    private Map<String,String> baiduData(String word){
        return baiduData(word,true);
    }

    private Map<String,String> baiduData(String word,boolean getQiniuFlag){
        Map data = new HashMap();
        try {
            //调取百度翻译接口
            JSONObject result = TransWebApi.trans(word);

            if(result == null){
                throw new RuntimeException("baidu: result is null");
            }

            if(result.getInteger("error") != null){
                data.put("error","-1");
                throw new RuntimeException(result.toString());
            }

            if(result.getJSONObject("dict_result") == null){
                data.put("error","baidu select null");
                throw new RuntimeException("baidu select null");
            }
            //数据解析封装
            JSONObject dict_result = result.getJSONObject("dict_result");
            JSONObject simple_means = dict_result.getJSONObject("simple_means");
            JSONArray symbols = simple_means.getJSONArray("symbols");
            JSONObject jsonObject = symbols.getJSONObject(0);
            String phAm = jsonObject.getString("ph_am");
            String phEn = jsonObject.getString("ph_en");
            logger.info("百度解析：" + word);
            logger.info("美式音标：" + phAm);
            logger.info("英式音标：" + phEn);
            data.put("phAm",phAm);
            data.put("phEn",phEn);
            //获取语音地址
            try {
                if(getQiniuFlag){
                    String audioUrlAm = baiduUploadToQiniu(word.trim(), "en");
                    data.put("audioUrlAm",audioUrlAm);
                    String audioUrlEn = baiduUploadToQiniu(word.trim(), "uk");
                    data.put("audioUrlEn",audioUrlEn);
                }
            } catch (Exception ioException) {
                logger.error("baidu: word upload error to Qiniu ---> word:{}",word,ioException);
            }

        } catch (Exception exception) {
            logger.error("baidu: word compensation trans error ---> word:{}",word,exception);
        }
        return data;
    }

    @Override
    public int updateByPrimaryKeySelective(CommonWordPronounce d) {
        return dao.updateByPrimaryKeySelective(d);
    }

    private String baiduUploadToQiniu(String word, String type) throws IOException {
        word = URLEncoder.encode(word, "UTF-8").replaceAll("\\+", "%20");

        String url = "https://fanyi.baidu.com/gettts?lan=" + type + "&text=" + word +"&spd=3&source=web";
        String fileName = "word/pronounce/" + type + "/" + word + ".mp3";

        QiniuImageUploader.MyRet ret = QiniuImageUploader.upload(FanyiV3Util.getByteFromUrl(url), fileName, bucket);
        System.out.println(ret.url.replaceAll("%2F", "/"));
        return ret.url.replaceAll("%2F", "/");
    }

    private String uploadToQiniu(String word, String type) throws IOException {
        word = URLEncoder.encode(word, "UTF-8").replaceAll("\\+", "%20");
        String url = "https://dict.youdao.com/dictvoice?audio=" + word + "&type=" + type;
        String fileName = "word/pronounce/" + type + "/" + word + ".mp3";

        QiniuImageUploader.MyRet ret = QiniuImageUploader.upload(FanyiV3Util.getByteFromUrl(url), fileName, bucket);
        System.out.println(ret.url.replaceAll("%2F", "/"));
        return ret.url.replaceAll("%2F", "/");
    }


}
